/*
 *   The contents of this file are subject to the Mozilla Public License
 *   Version 1.1 (the "License"); you may not use this file except in
 *   compliance with the License. You may obtain a copy of the License at
 *   http://www.mozilla.org/MPL/
 *
 *   Software distributed under the License is distributed on an "AS IS"
 *   basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 *   License for the specific language governing rights and limitations
 *   under the License.
 *
 *   The Original Code is Matra - the DTD Parser.
 *
 *   The Initial Developer of the Original Code is Conrad S Roche.
 *   Portions created by Conrad S Roche are Copyright (C) Conrad 
 *   S Roche. All Rights Reserved.
 *
 *   Alternatively, the contents of this file may be used under the terms
 *   of the GNU GENERAL PUBLIC LICENSE Version 2 or any later version
 *   (the  "[GPL] License"), in which case the
 *   provisions of GPL License are applicable instead of those
 *   above.  If you wish to allow use of your version of this file only
 *   under the terms of the GPL License and not to allow others to use
 *   your version of this file under the MPL, indicate your decision by
 *   deleting  the provisions above and replace  them with the notice and
 *   other provisions required by the GPL License.  If you do not delete
 *   the provisions above, a recipient may use your version of this file
 *   under either the MPL or the GPL License."
 *
 *   [NOTE: The text of this Exhibit A may differ slightly from the text of
 *   the notices in the Source Code files of the Original Code. You should
 *   use the text of this Exhibit A rather than the text found in the
 *   Original Code Source Code for Your Modifications.]
 *
 * Class Created: Conrad S Roche <derupe at users.sourceforge.net>,  26-Jul-2003
 * Methods Created: Conrad S Roche <derupe at users.sourceforge.net>,  25-Jul-2000 in Data.java
 */

package com.conradroche.matra.data;

/**
 * Class created by refactoring the Data class. It contains 
 * parsing related methods.
 * 
 * @author Conrad Roche
 */
public class ParseableData extends Data {

	/**
	 * ParseableData constructor.
	 */
	public ParseableData() {
		super();
	}

	/**
	 * ParseableData constructor.
	 * 
	 * @param strData The data to be parsed.
	 */
	public ParseableData(String strData) {
		super(strData);
	}

	/**
	 * Read the next token, delimited by a whitespace, from the data stream.
	 * @return The next token.
	 */
	public String getNextToken() {
	
		char nextChar;
		String name = "";
		
		while( !endOfData() && !isWhiteSpace(nextChar = lookNextChar()) )
			name += getNextChar();
	
		//read the space char
		getNextChar();
	
		return name;
	}

	/**
	 * Check if the current location starts with the 
	 * string specified.
	 * 
	 * @param str The string to check against.
	 * 
	 * @return <code>true</code> if the current location
	 * 		starts with the string specified; 
	 * 		<code>false</code> otherwise.
	 */
	public boolean nextStringEquals(String str) {	
		return nextStringEquals(str.toCharArray());
	}

	/**
	 * Check if the current location starts with the 
	 * string specified.
	 * 
	 * @param str The string to check against.
	 * 
	 * @return <code>true</code> if the current location
	 * 		starts with the string specified; 
	 * 		<code>false</code> otherwise.
	 */
	public boolean nextStringEquals(char[] str) {
		
		for(int i = 0; i < str.length; i++) {
			if(peekAhead(i + 1) != str[i]) {
				return false;
			}
		}
		
		return true;
	}
	
	/**
	 * Checks if the next token, delimited by whitespace,
	 * is equal to the specified string.
	 * 
	 * @param str String to check the next token against.
	 * 
	 * @return <code>true</code> if the next token in the 
	 * 		data stream is equal to the string specified;
	 * 		<code>false</code> otherwise. 
	 */
	public boolean nextTokenEquals(String str) {
		
		return nextTokenEquals(str.toCharArray());
	}
	
	/**
	 * Checks if the next token, delimited by whitespace,
	 * is equal to the specified string (char array).
	 * 
	 * @param str String to check the next token against.
	 * 
	 * @return <code>true</code> if the next token in the 
	 * 		data stream is equal to the string specified;
	 * 		<code>false</code> otherwise. 
	 */
	public boolean nextTokenEquals(char[] str) {

		if(!nextStringEquals(str)) {
			return false;
		}
		
		if(isWhiteSpace(peekAhead(str.length + 1))) {
			return true;
		}
		
		return false;
	}

	/**
	 * Read the next token, delimited by one of the specified 
	 * delimiters, from the data stream. 
	 * 
	 * @param delims The list of delimiters for the Token.
	 * 
	 * @return The next Token.
	 */
	public String getNextToken(char[] delims) {
	
		char nextChar;
		String name = "";
		int i;
		
		while( !endOfData() ) {
			nextChar = getNextChar();
			
			for(i = 0; i < delims.length; i++) {
				if(nextChar == delims[i])
					return name;
			}
			name += nextChar;
		}
	
		return name;
	}

	/**
	 * Read the next token, delimited by the specified delimiter, from the data stream.
	 * 
	 * @param delim The delimiter for the Token.
	 * 
	 * @return The next Token.
	 */
	public String getNextToken(char delim) {
	
		char nextChar;
		String name = "";
		
		while( !endOfData() && ( (nextChar = lookNextChar()) != delim ) )
			name += getNextChar();
	
		//read the delim char
		getNextChar();
	
		return name;
	}

	/**
	 * Read from the data stream while the char is among
	 * the one specified.
	 * 
	 * @param delims The list of characters to be skipped.
	 */
	public void skipChars(char[] delims) {
		
		if(delims == null || delims.length == 0) {
			return;
		}
		
		char nextChar;
		int i;
		boolean isDelim = true;
		
		while( !endOfData() && isDelim ) {
			nextChar = lookNextChar();
			isDelim = false;
			
			for(i = 0; i < delims.length; i++) {
				if(nextChar == delims[i]) {
					getNextChar();
					isDelim = true;
				}
			}
		}
	
	}

	/**
	 * Skip the next few chars.
	 * 
	 * @param numChars Number of characters to skip.
	 * 			<code>0</code> will not skip any characters.
	 * 			<code>1</code> will read and discard one charater.
	 */
	public void skipChars(int numChars) {
		
		if(numChars <= 0)
			return;
			
		//CR: NOTE: We cannot just move the current position
		//		since even the row/column position needs to be 
		//		calculated. This is a candidate for optimization
		for(int i = 0; i < numChars; i++) {
			getNextChar();
		}
	}
	
	/**
	 * Read from the data stream while the char is
	 * a whitespace character.
	 */
	public void skipWhiteSpace() {
	
		char junk;
		
		while( !endOfData() && isWhiteSpace( lookNextChar() ) )
			junk = getNextChar();
	}

	/**
	 * Check if the given char is a whitespace. Whitespace is 
	 * defined as the space, tab, linefeed and carriage return
	 * characters.
	 * 
	 * @param c The character to be checked.
	 * 
	 * @return <code>true</code> if the char is a whitespace char; if not returns <code>false</code>.
	 */
	public static boolean isWhiteSpace(char c) {
	
		//[3]   S    ::=    (#x20 | #x9 | #xD | #xA)+ 
		
		if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
			return true;
	
		return false;
	}
}
